package com.tools.common.object.type.handler;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.tools.common.container.*;
import com.tools.common.exception.ParseRuntimeException;
import com.tools.common.object.C;
import com.tools.common.object.Note;
import com.tools.common.object.ObjKit;
import com.tools.common.object.json.DeserializerHandler;
import com.tools.common.object.json.JsonKit;
import com.tools.common.object.string.VerifyKit;
import com.tools.common.object.type.CTKit;

import java.io.IOException;
import java.util.*;

/**
 * OwnPairs 集合的类型处理器
 * */
@Note("OwnPairs 集合的类型处理器")
public final class PairTypeHandler {

    private PairTypeHandler() {}

    /* ************************************************************************************************************
     *
     *          转换的功能方法
     *
     * ************************************************************************************************************
     * */

    @Note("将 source 转换为 OwnPairs 集合")
    public static OwnPairs castToOwnPairs(Object source, C<?> targetType) {
        Class<?> mainType = targetType.getMainType();
        if(OwnMap.class.equals(mainType) || OwnPairs.class.equals(mainType) || AbsOwnPair.class.equals(mainType)) {
            return ownMap(source, targetType);
        }
        if(OwnPair.class.equals(mainType)) {
            return ownPair(source, targetType);
        }
        if(JsonPair.class.equals(mainType)) {
            return jsonPair(source, targetType);
        }
        return otherOwnPair(source, targetType);
    }


    @Note("使用 JsonParser 流模式将 JSON 转为 OwnPairs 集合")
    public static OwnPairs castToOwnPairs(JsonParser parser, C<?> targetType) {
        Class<?> mainType = targetType.getMainType();
        try {
            if(OwnMap.class.equals(mainType) || OwnPairs.class.equals(mainType) || AbsOwnPair.class.equals(mainType)) {
                if(targetType.argCount() == 0) {
                    return private_putInPairs(parser, new OwnMap(MapEnum.LINKED), targetType);
                }
                OwnMap pair = ownMap(targetType);
                return private_putInPairs(parser, pair, targetType);
            }
            if(OwnPair.class.equals(mainType)) {
                OwnPair pair = ownPair(targetType);
                return private_putInPairs(parser, pair, targetType);
            }
            if(JsonPair.class.equals(mainType)) {
                JsonPair pair = jsonPair(targetType);
                return private_putInPairs(parser, pair, targetType);
            }
            OwnPairs pairs = (OwnPairs) ObjKit.buildObject(targetType);
            return private_putInPairs(parser, pairs, targetType);
        } catch (Exception e) {
            throw new ParseRuntimeException(e);
        }
    }


    /* ************************************************************************************************************
     *
     *          构建空集合的方法
     *
     * ************************************************************************************************************
     * */

    @Note("创建空的 OwnMap 集合")
    public static OwnMap ownMap(C<?> targetType) {
        Object first = targetType.getArgValue(0);
        if(first instanceof Integer) {
            return new OwnMap((Integer) first);
        }
        if(first instanceof Map) {
            return new OwnMap((Map) first);
        }
        if(first instanceof OwnPairs) {
            return new OwnMap((OwnPairs) first);
        }
        if(first instanceof MapEnum) {
            MapEnum f = (MapEnum) first;
            Object second = targetType.getArgValue(1);
            if(second instanceof Integer) {
                Integer s = (Integer) second;
                Object third = targetType.getArgValue(2);
                if(third instanceof Comparator) {
                    return new OwnMap(f, s, (Comparator) third);
                }
                if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                    return new OwnMap(f, s, DeserializerHandler.getDefaultComparator());
                }
                return new OwnMap(f, s);
            }
            if(second instanceof Comparator) {
                return new OwnMap(f, (Comparator) second);
            }
            if(second instanceof Map) {
                Map s = (Map) second;
                Object third = targetType.getArgValue(2);
                if(third instanceof Comparator) {
                    return new OwnMap(f, s, (Comparator) third);
                }
                else if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                    return new OwnMap(f, s, DeserializerHandler.getDefaultComparator());
                }
                return new OwnMap(f, s);
            }
            if(second instanceof OwnPairs) {
                OwnPairs s = (OwnPairs) second;
                Object third = targetType.getArgValue(2);
                if(!(third instanceof Comparator)) {
                    if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                        return new OwnMap(f, s, DeserializerHandler.getDefaultComparator());
                    }
                    return new OwnMap(f, s);
                }
                return new OwnMap(f, s, (Comparator) third);
            }
            if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                return new OwnMap(f, DeserializerHandler.getDefaultComparator());
            }
            return new OwnMap(f);
        }
        return new OwnMap<>();
    }


    @Note("创建空的 OwnPair 集合")
    public static OwnPair ownPair(C<?> targetType) {
        Object first = targetType.getArgValue(0);
        if(first instanceof Integer) {
            return new OwnPair((Integer) first);
        }
        if(first instanceof Map) {
            return new OwnPair((Map) first);
        }
        if(first instanceof OwnPairs) {
            return new OwnPair((OwnPairs) first);
        }
        if(first instanceof MapEnum) {
            MapEnum f = (MapEnum) first;
            Object second = targetType.getArgValue(1);
            if(second instanceof Integer) {
                Integer s = (Integer) second;
                Object third = targetType.getArgValue(2);
                if(third instanceof Comparator) {
                    return new OwnPair(f, s, (Comparator) third);
                }
                if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                    return new OwnPair(f, s, DeserializerHandler.getDefaultComparator());
                }
                return new OwnPair(f, s);
            }
            if(second instanceof Comparator) {
                return new OwnPair(f, (Comparator) second);
            }
            if(second instanceof Map) {
                Map s = (Map) second;
                Object third = targetType.getArgValue(2);
                if(third instanceof Comparator) {
                    return new OwnPair(f, s, (Comparator) third);
                }
                else if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                    return new OwnPair(f, s, DeserializerHandler.getDefaultComparator());
                }
                return new OwnPair(f, s);
            }
            if(second instanceof OwnPairs) {
                OwnPairs s = (OwnPairs) second;
                Object third = targetType.getArgValue(2);
                if(!(third instanceof Comparator)) {
                    if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                        return new OwnPair(f, s, DeserializerHandler.getDefaultComparator());
                    }
                    return new OwnPair(f, s);
                }
                return new OwnPair(f, s, (Comparator) third);
            }
            if(f == MapEnum.TREE || f == MapEnum.SKIP_LIST) {
                return new OwnPair(f, DeserializerHandler.getDefaultComparator());
            }
            return new OwnPair(f);
        }
        return new OwnPair();
    }



    @Note("构建空的 JsonPair 集合")
    public static JsonPair jsonPair(C<?> targetType) {
        Object first = targetType.getArgValue(0);
        Object second = targetType.getArgValue(1);
        if(first instanceof Integer) {
            Integer code = (Integer) first;
            String message = (second == null) ? "" : second.toString();
            Object third = targetType.getArgValue(2);
            if(third != null) {
                return new JsonPair(code, message, third);
            }
            return new JsonPair(code, message);
        }
        return new JsonPair();
    }



    /* ************************************************************************************************************
     *
     *          构建完整数据集合的功能方法
     *
     * ************************************************************************************************************
     * */



    @Note("生成 OwnMap 集合")
    public static OwnMap ownMap(Object source, C<?> targetType) {
        Class<?> sourceClass = source.getClass();
        if(Map.class.isAssignableFrom(sourceClass)) {
            OwnMap ownMap = ownMap(targetType);
            CTKit.mapToOwnPairsFillIn((Map) source, ownMap, targetType);
            return ownMap;
        }
        if(OwnPairs.class.isAssignableFrom(sourceClass)) {
            OwnMap ownMap = ownMap(targetType);
            CTKit.pairsToOwnPairsFillIn((OwnPairs) source, ownMap, targetType);
            return ownMap;
        }
        if(String.class.equals(sourceClass)) {
            String json = (String) source;
            if(VerifyKit.isJsonObject(json)) {
                return (OwnMap) ObjKit.jsonParserToRealValue(json, targetType);
            }
            throw new ClassCastException("无法将非对象类型的 JSON 字符串 【" + json + "】 转为 com.tools.common.container.OwnMap");
        }
        Map<String, Object> map = ObjKit.allFieldValue(source);
        OwnMap ownMap = ownMap(targetType);
        CTKit.mapToOwnPairsFillIn(map, ownMap, targetType);
        return ownMap;
    }


    @Note("生成 OwnPair 集合")
    public static OwnPair ownPair(Object source, C<?> targetType) {
        Class<?> sourceClass = source.getClass();
        if(Map.class.isAssignableFrom(sourceClass)) {
            OwnPair ownPair = ownPair(targetType);
            CTKit.mapToOwnPairsFillIn((Map) source, ownPair, targetType);
            return ownPair;
        }
        if(OwnPairs.class.isAssignableFrom(sourceClass)) {
            OwnPair ownPair = ownPair(targetType);
            CTKit.pairsToOwnPairsFillIn((OwnPairs) source, ownPair, targetType);
            return ownPair;
        }
        if(String.class.equals(sourceClass)) {
            String json = (String) source;
            if(VerifyKit.isJsonObject(json)) {
                return (OwnPair) ObjKit.jsonParserToRealValue(json, targetType);
            }
            throw new ClassCastException("无法将非对象类型的 JSON 字符串 【" + json + "】 转为 com.tools.common.container.OwnPair");
        }
        Map<String, Object> map = ObjKit.allFieldValue(source);
        OwnPair ownPair = ownPair(targetType);
        CTKit.mapToOwnPairsFillIn(map, ownPair, targetType);
        return ownPair;
    }


    @Note("生成 JsonPair 集合")
    public static JsonPair jsonPair(Object source, C<?> targetType) {
        Class<?> sourceClass = source.getClass();
        if(Map.class.isAssignableFrom(sourceClass)) {
            JsonPair jsonPair = jsonPair(targetType);
            CTKit.mapToOwnPairsFillIn((Map) source, jsonPair, targetType);
            return jsonPair;
        }
        if(OwnPairs.class.isAssignableFrom(sourceClass)) {
            JsonPair pair = jsonPair(targetType);
            CTKit.pairsToOwnPairsFillIn((OwnPairs) source, pair, targetType);
            return pair;
        }
        if(String.class.equals(sourceClass)) {
            String json = (String) source;
            if(VerifyKit.isJsonObject(json)) {
                return (JsonPair) ObjKit.jsonParserToRealValue(json, targetType);
            }
            throw new ClassCastException("无法将非对象类型的 JSON 字符串 【" + json + "】 转为 com.tools.common.container.JsonPair");
        }
        Map<String, Object> map = ObjKit.allFieldValue(source);
        JsonPair pair = jsonPair(targetType);
        CTKit.mapToOwnPairsFillIn(map, pair, targetType);
        return pair;
    }


    @Note("生成其他未知类型的 OwnPairs 集合")
    public static OwnPairs otherOwnPair(Object source, C<?> targetType) {
        Class<?> sourceClass = source.getClass();
        if(Map.class.isAssignableFrom(sourceClass)) {
            OwnPairs pairs = (OwnPairs) ObjKit.buildObject(targetType);
            CTKit.mapToOwnPairsFillIn((Map) source, pairs, targetType);
            return pairs;
        }
        if(OwnPairs.class.isAssignableFrom(sourceClass)) {
            OwnPairs pairs = (OwnPairs) ObjKit.buildObject(targetType);
            CTKit.pairsToOwnPairsFillIn((OwnPairs) source, pairs, targetType);
            return pairs;
        }
        if(String.class.equals(sourceClass)) {
            String json = (String) source;
            if(VerifyKit.isJsonObject(json)) {
                return (OwnPairs) ObjKit.jsonParserToRealValue(json, targetType);
            }
            throw new ClassCastException("无法将非对象类型的 JSON 字符串 【" + json + "】 转为 " + targetType.getMainType().getName());
        }
        Map<String, Object> map = ObjKit.allFieldValue(source);
        OwnPairs pairs = (OwnPairs) ObjKit.buildObject(targetType);
        CTKit.mapToOwnPairsFillIn(map, pairs, targetType);
        return pairs;
    }


    /* *******************************************************************************************
     *
     *          私有逻辑
     *
     * *******************************************************************************************
     * */

    @Note("私有逻辑：将 JsonParser 转为 OwnPairs 集合的具体逻辑")
    private static OwnPairs private_putInPairs(JsonParser parser, OwnPairs pair, C<?> targetType) throws IOException {
        if(targetType.hasGenericType()) {
            C<?> keyType = targetType.generic(0);
            C<?> valueType = targetType.generic(1);
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                if (parser.currentToken() == JsonToken.FIELD_NAME) {
                    String fieldName = parser.getCurrentName();
                    parser.nextToken();
                    Object key = ObjKit.stringToRealValue(fieldName, keyType);
                    Object value = JsonKit.parseToken(parser, valueType);
                    pair.put(key, ObjKit.toRealValue(value, valueType));
                }
            }
            return pair;
        }
        while (parser.nextToken() != JsonToken.END_OBJECT) {
            if (parser.currentToken() == JsonToken.FIELD_NAME) {
                String fieldName = parser.getCurrentName();
                parser.nextToken();
                pair.put(fieldName, JsonKit.parseToken(parser));
            }
        }
        return pair;
    }
}
